module i2c_top(
  input         sys_clk,
  input         button,
  output  [7:0] led,
  output        scl,
  inout         sda
);

// ----------------------clocking----------------------
wire clk_50M;
wire sys_clk_ibufg, clk_out;
// IBUFDS IBUFDS_inst_sys_clock(
//   .O(sys_clk_ibufg), 
//   .I(sys_clk_p), 
//   .IB(sys_clk_n));
   
// BUFG BUFG_inst_sys_clock (
//       .O(sys_clk), // 200MHz
//       .I(sys_clk_ibufg));

// pll 200MHz in 50M out
assign clk_50M = sys_clk;
// ----------------------------------------------------

// ------------------------reset_n---------------------
wire rst_n;
// reset for several second
reset reset_m0(
  .clk(clk_50M),
  .rst_n(rst_n)
);
// ----------------------------------------------------

// ------------------------10ms clock------------------
reg         clk_10ms;
reg  [19:0] cnt_10ms;
always @(posedge clk_50M) begin
  if (!rst_n) begin
    cnt_10ms <= 0;
    clk_10ms <= 0;
  end else
    if (cnt_10ms < 20'd50) begin // 500_000
      cnt_10ms <= cnt_10ms + 1;
      clk_10ms <= clk_10ms;
    end else begin
      cnt_10ms <= 0;
      clk_10ms <= ~clk_10ms;
    end 
end
// ----------------------------------------------------

// ------------------------button----------------------
wire button_rise;
reg button_d0, button_d1, button_d2;
always @(posedge clk_10ms) begin
  if (!rst_n) begin
    button_d0 <= 0;
    button_d1 <= 0;
  end else begin
    button_d0 <= ~button;
    button_d1 <= button_d0;
  end
end
always @(posedge clk_50M) begin
  if (!rst_n) 
    button_d2 <= 0;
  else 
    button_d2 <= button_d1;
end

assign button_rise = (button_d1) && (~button_d2);
// ----------------------------------------------------

// ---------------------instruction counter------------
reg [2:0] cnt;
always @(posedge clk_50M) begin
  if (!rst_n) 
    cnt <= 0;
  else if (button_rise) 
    cnt <= cnt + 1;
  else 
    cnt <= cnt;
end
// ----------------------------------------------------


// ---------------------state machine------------------
reg [11:0] data_pre_cnt;
wire tran_done;

reg [2:0] state, next_state;
parameter idle    = 3'd0;
parameter load    = 3'd1;
parameter waits   = 3'd2;

always @(posedge clk_50M) begin
  if (!rst_n) 
    state <= idle;
  else 
    state <= next_state;
end

always @(*) begin
  case (state)
  idle:     if (button_rise)
              next_state <= load; 
            else 
              next_state <= idle;
  load:     if (data_pre_cnt > 11'd2000)
              next_state <= waits;
            else 
              next_state <= load;
  waits:    if (tran_done)
              next_state <= idle;
            else 
              next_state <= waits;
  default:  next_state <= idle;
  endcase
end
// ----------------------------------------------------

// --------------------data prepare count--------------
always @(posedge clk_50M) begin
  if ((!rst_n) || (state == idle))
    data_pre_cnt <= 0;
  else if (state == load)
    data_pre_cnt <= data_pre_cnt + 1;
  else data_pre_cnt <= data_pre_cnt;
end

wire load_data, data_valid_start, data_valid_end;
assign load_data = (data_pre_cnt == 11'd200);
assign data_valid_start = (data_pre_cnt == 11'd300);
assign data_valid_end = (data_pre_cnt == 11'd1800);
// ----------------------------------------------------

// -----------------load data--------------------------
reg mode;
reg [7:0] devaddr, subaddr, data_in;
always @(posedge clk_50M) begin
  if (!rst_n) begin
    mode <= 0; devaddr <= 0; subaddr <= 0; data_in <= 0;
  end
  if (load_data) begin
  case (cnt)
    3'd0:     begin mode <= 1; devaddr <= 8'h98; subaddr<= 8'hFF; data_in<= 0; end
    3'd1:     begin mode <= 0; devaddr <= 8'hAE; subaddr<= 8'hA0; data_in<= 8'h31; end
    3'd2:     begin mode <= 0; devaddr <= 8'hAE; subaddr<= 8'hB0; data_in<= 8'h13; end
    3'd3:     begin mode <= 1; devaddr <= 8'hAE; subaddr<= 8'hA0; data_in<= 0; end
    3'd4:     begin mode <= 1; devaddr <= 8'hAE; subaddr<= 8'hB0; data_in<= 0; end
    default:  begin mode <= 1; devaddr <= 8'h98; subaddr<= 8'hFF; data_in<= 0; end
  endcase
  end
end
// ----------------------------------------------------

// ----------------------data valid--------------------
reg data_valid;
always @(posedge clk_50M) begin
  if (!rst_n)
    data_valid <= 0;
  else if (data_valid_start)
    data_valid <= 1;
  else if (data_valid_end)
    data_valid <= 0;
  else 
    data_valid <= data_valid;
end
// -----------------------------------------------------

// ---------------------connect i2c tran module---------
wire ack_r;
wire [7:0] data_out;
i2c_tran u1(
  .clk_50M(clk_50M), .rst_n(rst_n),
  .data_valid(data_valid), .mode(mode),
  .devaddr(devaddr), .subaddr1(8'h00), .subaddr2(subaddr), .data_in(data_in),
  .tran_done(tran_done), .data_out(data_out), 
  .scl(scl), .sda(sda),
  .ack_r(ack_r));
// -----------------------------------------------------

// ---------------------------led-----------------------
assign led[7]   = button_d2;
assign led[6]   = (state == idle);
assign led[5]   = data_valid;
assign led[4]   = ack_r;
assign led[3]   = 0;
assign led[2:0] = cnt;
// ----------------------------------------------------
endmodule